#include "text.h"

using namespace G3;

//==============================================================================
// Constructors
//==============================================================================
G3::STR_REPLACEMENT::STR_REPLACEMENT () {
	Start = 0;
	Length = 0;
	
	UserData = NULL;
}

//==============================================================================
// Operators
//==============================================================================
STR_REPLACEMENT& G3::STR_REPLACEMENT::operator=(const STR_REPLACEMENT &str) {
	Start = str.Start;
	Length = str.Length;
	Old = str.Old;
	New = str.New;
	UserData = str.UserData;
	
	return *this;
}

bool G3::STR_REPLACEMENT::operator<(const STR_REPLACEMENT &str) const {
	if (Start < str.Start)
		return true;
	if (Length < str.Length)
		return true;
	return false;
}

bool G3::STR_REPLACEMENT::operator==(const STR_REPLACEMENT &str) const {
	return (Old == str.Old);
}

string G3::TOKENLIST::operator[](const int &id) const {
    if (id < size ())
        return Tokens [id];
    return "";
}

TOKENLIST& G3::TOKENLIST::operator=(const TOKENLIST &tokl) {
	if (!Tokens.empty ())
		Tokens.clear ();
	if (!Delims.empty ())
		Delims.clear ();
	
	Tokens = tokl.Tokens;
	Delims = tokl.Delims;
	
	return *this;
}

//==============================================================================
// Clears the tokenlist
//==============================================================================
void G3::TOKENLIST::clear () {
    Tokens.clear ();
	Delims.clear ();
}

//==============================================================================
// Gets the number of tokens in the list
//==============================================================================
int G3::TOKENLIST::size () const {
    return Tokens.size ();
}

//==============================================================================
// Removes trailing whitespaces and tabs from str
//
//	TODO:: Implement one with erase instead of substr - faster
//==============================================================================
string G3::TrimString (string str) {
	size_t start = str.find_first_not_of (" \t\r\n");
	size_t end = str.find_last_not_of (" \t\r\n");
	
	if (start == string::npos || end == string::npos)
		return "";
	
	return str.substr (start, end - start + 1);
}

//==============================================================================
// Removes trailing delimiters from Str
//==============================================================================
string G3::TrimDelimiters (const string &Str, const string &Delims) {
	string Ret;
	
	// Empty strings?
	if (Str == "" || Delims == "")
		return Ret;
	
	// Only 1 character?
	if (Str.size () == 1) {
		if (Delims.find (Str, 0) == string::npos)
			Ret = Str;
		return Ret;
	}
	
	size_t Start = Str.find_first_not_of (Delims, 0);
	size_t End = Str.find_last_not_of (Delims, Str.size () - 1);
	
	// There is something left in that string, isn't there?
	if (Start != End)
		Ret = Str.substr (Start, End + 1);

	return Ret;
}

//==============================================================================
// Copies until a certain delimiter occurs
//==============================================================================
string G3::CopyUntilDelim (const string &str, const string &delim) {
	size_t pos = str.find (delim, 0);
	string ret;
	
	if (pos == string::npos)
		ret = str;
	else
		ret = str.substr (0, pos);

	return ret;
}

//==============================================================================
// Copies until one of the characters occur
//==============================================================================
string G3::CopyUntilDelims (const string &str, const string &delims) {
	size_t pos = str.find_first_of (delims, 0);
	string ret;
	
	if (pos == string::npos)
		ret = str;
	else
		ret = str.substr (0, pos);

	return ret;
}

//==============================================================================
// Starts copying the characters after one of the delimiters have occurred
//==============================================================================
string G3::CopyAfterDelims (const string &str, const string &delims) {
	size_t pos1 = str.find_first_of (delims, 0);
	
	if (pos1 == string::npos)
		return "";
	
	size_t pos2 = str.find_first_not_of (delims, pos1);
	
	if (pos2 == string::npos)
		return "";
	
	return str.substr (pos2, string::npos);
}

//==============================================================================
// Tokenizes an STL string
//==============================================================================
TOKENLIST G3::Tokenize (const string &str, const string &delimiters) {
	TOKENLIST tokl;
    	
	// skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of (delimiters, 0);
	
	// store delimiters
	if (string::npos != lastPos && lastPos > 0)
		tokl.Delims.push_back (str.substr (0, lastPos - 1));
	else if (string::npos == lastPos){
		tokl.Delims.push_back ("");
		tokl.Delims.push_back (str);
		tokl.Tokens.push_back ("");
		return tokl;
	} else {
		tokl.Delims.push_back ("");
	}

	// find first delimiter.
    string::size_type pos = str.find_first_of (delimiters, lastPos);
	
    while (string::npos != pos || string::npos != lastPos) {
        // found a token, add it to the vector.
        tokl.Tokens.push_back (str.substr (lastPos, pos - lastPos));
		
        // skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of (delimiters, pos);
		
		// store delimiters
		if (string::npos != pos) {
			if (string::npos != lastPos)
				tokl.Delims.push_back (str.substr (pos, lastPos - pos));
			else
				tokl.Delims.push_back (str.substr (pos, str.size () - pos));
		} else {
			tokl.Delims.push_back ("");
		}
			
        // find next delimiter
        pos = str.find_first_of (delimiters, lastPos);
    }
	return tokl;
}

//==============================================================================
// Finds the number of substring occurrences in a string
//==============================================================================
int G3::CountSubstrings (const string &str, const string &substr) {
	size_t pos = 0;
	int count = 0;
	
	while (true) {
		pos = str.find (substr, pos);
		
		if (pos != string::npos)
			count++;
		else
			break;

		pos++;
	}

	return count;
}

//==============================================================================
// Finds the number of substring occurrences in a string and erases them
//==============================================================================
int G3::CountAndEraseSubstrings (string &str, const string &substr) {
	size_t pos = 0;
	int count = 0;
	
	while (true) {
		pos = str.find (substr, pos);
		
		if (pos != string::npos) {
			count++;
			str.erase (pos, 1);
		} else
			break;

		pos++;
	}

	return count;
}

//==============================================================================
// Indents the string to a given depth
//==============================================================================
std::string G3::IndentStr (const std::string &str, const uint &depth, const char c) {
	std::string ret;

	for (uint i=0; i<depth; i++)
		ret += c;

	return ret + str;
}

//==============================================================================
// Returns true if the string is a decimal or float
//==============================================================================
bool G3::IsNumber (string str) {
	if (str == "")
		return false;
	
	for (int i=0; i<str.size (); i++) {
		if (!isdigit (str [i]) && str [i] != '-' && str [i] != '.')
			return false;
	}
	return true;
}

//==============================================================================
// Returns true if the string is a decimal
//==============================================================================
bool G3::IsDecimal (string str) {
	if (str == "")
		return false;
	
	for (int i=0; i<str.size (); i++) {
		if (!isdigit (str [i]) && str [i] != '-')
			return false;
	}
	return true;
}

//==============================================================================
// Returns true if the string contains text characters
//==============================================================================
bool G3::IsText (string str) {
	if (str == "")
		return false;
	
	for (int i=0; i<str.size (); i++) {
		if (isalpha (str [i]))
			return true;
	}
	return false;
}

//==============================================================================
// Makes a string -> long integer conversion
//==============================================================================
long G3::StrToInteger (string str) {
    long i = 0;

    istringstream iss (str);
    iss >> i;

    return i;
}

//==============================================================================
// Makes a string -> float conversion
//==============================================================================
float G3::StrToFloat (string str) {
    float i = 0;

    istringstream iss (str);
    iss >> i;

    return i;
}

//==============================================================================
// Makes a string -> double conversion
//==============================================================================
double G3::StrToDouble (string str) {
    double i = 0;

    istringstream iss (str);
    iss >> i;

    return i;
}

//==============================================================================
// Makes a  integer -> string conversion
//==============================================================================
string G3::IntegerToStr (long i) {
    ostringstream oss;

    oss << i;

    return oss.str ();
}

//==============================================================================
// Makes a float -> string conversion
//==============================================================================
string G3::FloatToStr (float f) {
    ostringstream oss;

    oss << f;

    return oss.str ();
}

//==============================================================================
// Makes a double -> string conversion
//==============================================================================
string G3::DoubleToStr (double d) {
    ostringstream oss;

    oss << d;

    return oss.str ();
}
